package integral

import (
	"crypto/rand"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"higame/config"
	"higame/modules/store"
	"higame/modules/utils"
	"higame/routes/log"
	"higame/routes/user"
	"math/big"
	"path"
	"strings"
)

func getTaskList() bson.A {
	time := utils.Timestamp()
	return bson.A{
		&TaskSchema{
			AddTime:  time,
			TaskID:   uuid.NewV1().String(),
			TaskName: "CHECK_IN",
			Title:    "每日签到",
			Subtitle: "每日签到得积分",
			EXP:      10,
			Integral: 10,
			IsLoop:   true,
		},
		&TaskSchema{
			AddTime:  time,
			TaskID:   uuid.NewV1().String(),
			TaskName: "SHARE",
			Title:    "软件分享",
			Subtitle: "复制邀请码分享给你的好友",
			EXP:      50,
			Integral: 50,
			IsLoop:   true,
		},
		&TaskSchema{
			AddTime:  time,
			TaskID:   uuid.NewV1().String(),
			TaskName: "FIRST_LOGIN",
			Title:    "首次注册",
			Subtitle: "第一次注册成功，并且成功登录。",
			EXP:      100,
			Integral: 100,
			IsLoop:   false,
		},
		&TaskSchema{
			AddTime:  time,
			TaskID:   uuid.NewV1().String(),
			TaskName: "FOLLOW_WX",
			Title:    "关注微信",
			Subtitle: "关注微信，第一时间获取动态",
			EXP:      50,
			Integral: 50,
			IsLoop:   false,
		},
		&TaskSchema{
			AddTime:  time,
			TaskID:   uuid.NewV1().String(),
			TaskName: "BIND_EMAIL",
			Title:    "绑定您的邮箱",
			Subtitle: "用于找回密码、帐号信息修改确认等",
			EXP:      20,
			Integral: 20,
			IsLoop:   false,
		},
		&TaskSchema{
			AddTime:  time,
			TaskID:   uuid.NewV1().String(),
			TaskName: "BIND_ALIPAY",
			Title:    "绑定您的支付宝",
			Subtitle: "用于积分提现与积分充值",
			EXP:      20,
			Integral: 20,
			IsLoop:   false,
		},
		&TaskSchema{
			AddTime:  time,
			TaskID:   uuid.NewV1().String(),
			TaskName: "UPLOAD_AVATAR",
			Title:    "上传个人头像",
			Subtitle: "脸换不了，换张喜欢的头像还是easy的",
			EXP:      20,
			Integral: 20,
			IsLoop:   false,
		},
		&TaskSchema{
			AddTime:  time,
			TaskID:   uuid.NewV1().String(),
			TaskName: "PLAY_GAME",
			Title:    "下载游戏",
			Subtitle: "下载游戏并玩一款游戏",
			EXP:      100,
			Integral: 100,
			IsLoop:   false,
		},
	}
}

func getPrizeList() bson.A {
	return bson.A{
		&PrizeSchema{
			Name:  "no1",
			Title: "一等奖",
			Odds:  0.1,
			Prize: 10000,
		},
		&PrizeSchema{
			Name:  "no2",
			Title: "二等奖",
			Odds:  0.3,
			Prize: 5000,
		},
		&PrizeSchema{
			Name:  "no3",
			Title: "三等奖",
			Odds:  0.6,
			Prize: 3000,
		},
		&PrizeSchema{
			Name:  "no4",
			Title: "四等奖",
			Odds:  1,
			Prize: 1000,
		},
		&PrizeSchema{
			Name:  "no5",
			Title: "五等奖",
			Odds:  2,
			Prize: 500,
		},
		&PrizeSchema{
			Name:  "no6",
			Title: "六等奖",
			Odds:  21,
			Prize: 50,
		},
		&PrizeSchema{
			Name:  "no7",
			Title: "七等奖",
			Odds:  35,
			Prize: 20,
		},
		&PrizeSchema{
			Name:  "no8",
			Title: "八等奖",
			Odds:  40,
			Prize: 0,
		},
	}
}

func validatorForUpdateTask(ctx *gin.Context) (*TaskSchema, error) {
	v := NewTaskSchema()
	err := ctx.ShouldBind(v)
	if err != nil {
		errText := err.Error()
		var msgList [] string
		if strings.Contains(errText, "'Integral' failed on the 'required' tag") {
			msgList = append(msgList, "用户名不能为空")
		}

		if strings.Contains(errText, "'EXP' failed on the 'required' tag") {
			msgList = append(msgList, "密码不能为空")
		}
		if len(msgList) > 0 {
			return nil, errors.New(strings.Join(msgList, "，") + "。")
		}
	}
	return v, nil
}

func validatorForSetPrize(ctx *gin.Context) (*PrizeSchema, error) {
	v := &PrizeSchema{}
	err := ctx.ShouldBind(v)
	if err != nil {
		errText := err.Error()
		var msgList [] string
		if strings.Contains(errText, "'Name' failed on the 'required' tag") {
			msgList = append(msgList, "参数出错")
		}

		if len(msgList) > 0 {
			return nil, errors.New(strings.Join(msgList, "，") + "。")
		}
	}
	return v, nil
}

func taskHandler(ctx *gin.Context) (string, error) {
	claims, err := store.GetClaims(ctx)
	if err != nil {
		return "", err
	}

	taskID := ctx.PostForm("task_id")
	task, err := FindOneByTaskID(taskID)
	if err != nil {
		return "", err
	}

	switch task.TaskName {
	case "CHECK_IN":
		return "", checkIn(claims.Audience)
	case "SHARE":
		return share(claims.Audience)
	case "FIRST_LOGIN":
		return "", firstLogin(claims.Audience)
	case "FOLLOW_WX":
		return "", followWX(claims.Audience)
	case "BIND_EMAIL":
		email := ctx.PostForm("data")
		return "", bindEmail(claims.Audience, email)
	case "BIND_ALIPAY":
		alipay := ctx.PostForm("data")
		return "", bindAlipay(claims.Audience, alipay)
	case "UPLOAD_AVATAR":
		avatar := ctx.PostForm("data")
		return "", bindAvatar(claims.Audience, avatar)
	case "PLAY_GAME":
		return "", playGame(claims.Audience)
	}
	return "", errors.New("参数出错")
}

func checkIn(username string) error {
	text := "每日签到"
	taskName := "CHECK_IN"
	// 获取任务配置
	task, err := FindOneByTaskName("CHECK_IN")
	if err != nil {
		return errors.New("没有找到这个任务！")
	}

	// 判读今天是否已经完成任务
	logs := log.FindManyIntegralLog(0, bson.M{
		"username": username,
		"text":     text,
		"add_time": bson.M{
			"$gt": utils.DayStartTime(0),
			"$lt": utils.DayStartTime(1),
		},
	})
	if len(logs) > 0 {
		return errors.New("你今天已经签到过了，明天再来吧！")
	}

	// 修改用户积分数据
	if err := user.UpdateOne(bson.M{
		"username": username,
	}, bson.M{
		"$inc": bson.M{
			"integral": task.Integral,
		},
	}); err != nil {
		return err
	}

	// 添加积分日志

	if err := log.AddOneIntegralLog(&log.IntegralLogSchema{
		UUID:     uuid.NewV1().String(),
		AddTime:  utils.Timestamp(),
		Username: username,
		Integral: task.Integral,
		Text:     text,
		Other:    "任务完成",
		Remark:   taskName,
	}); err != nil {
		return err
	}
	return nil
}

func share(username string) (string, error) {

	u, err := user.FindOneByName(username)
	if err != nil {
		return "", err
	}

	return utils.JoinString("下载HiGame游戏客户端，免费畅玩多款游戏私服，免费下载单机游戏大作。\n下载地址：%s\n注册输入邀请码：%s", "[downURL]", u.ShareCode), nil
}
func followWX(username string) error {
	return errors.New("任务没有开通")
}
func firstLogin(username string) error {
	text := "首次登录"
	taskName := "FIRST_LOGIN"
	// 获取任务配置
	task, err := FindOneByTaskName("FIRST_LOGIN")
	if err != nil {
		return errors.New("没有找到这个任务！")
	}

	// 判读是否已经完成任务
	logs := log.FindManyIntegralLog(0, bson.M{
		"username": username,
		"text":     text,
	})
	if len(logs) > 0 {
		return errors.New("你已经完成任务！")
	}

	// 修改用户积分数据
	if err := user.UpdateOne(bson.M{
		"username": username,
	}, bson.M{
		"$inc": bson.M{
			"integral": task.Integral,
		},
	}); err != nil {
		return err
	}

	// 添加积分日志

	if err := log.AddOneIntegralLog(&log.IntegralLogSchema{
		UUID:     uuid.NewV1().String(),
		AddTime:  utils.Timestamp(),
		Username: username,
		Integral: task.Integral,
		Text:     text,
		Other:    "任务完成",
		Remark:   taskName,
	}); err != nil {
		return err
	}
	return nil
}

func bindEmail(username string, email string) error {
	if !utils.IsEmail(email) {
		return errors.New("请输入正确的E-mail")
	}

	text := "绑定邮箱"
	taskName := "BIND_EMAIL"
	// 获取任务配置
	task, err := FindOneByTaskName("BIND_EMAIL")
	if err != nil {
		return errors.New("没有找到这个任务！")
	}

	// 判读是否已经完成任务
	logs := log.FindManyIntegralLog(0, bson.M{
		"username": username,
		"text":     text,
	})
	if len(logs) > 0 {
		return errors.New("你已经完成任务！")
	}

	if err := user.UpdateOneByName(username, bson.M{
		"email": email,
	}); err != nil {
		return err
	}

	// 修改用户积分数据
	if err := user.UpdateOne(bson.M{
		"username": username,
	}, bson.M{
		"$inc": bson.M{
			"integral": task.Integral,
		},
	}); err != nil {
		return err
	}
	// 添加积分日志

	if err := log.AddOneIntegralLog(&log.IntegralLogSchema{
		UUID:     uuid.NewV1().String(),
		AddTime:  utils.Timestamp(),
		Username: username,
		Integral: task.Integral,
		Text:     text,
		Other:    "任务完成",
		Remark:   taskName,
	}); err != nil {
		return err
	}
	return nil
}

func bindAlipay(username string, alipay string) error {
	if alipay == "" {
		return errors.New("参数出错")
	}
	text := "绑定支付宝"
	taskName := "BIND_ALIPAY"
	// 获取任务配置
	task, err := FindOneByTaskName("BIND_ALIPAY")
	if err != nil {
		return errors.New("没有找到这个任务！")
	}

	// 判读是否已经完成任务
	logs := log.FindManyIntegralLog(0, bson.M{
		"username": username,
		"text":     text,
	})
	if len(logs) > 0 {
		return errors.New("你已经完成任务！")
	}

	if err := user.UpdateOneByName(username, bson.M{
		"alipay": alipay,
	}); err != nil {
		return err
	}

	// 修改用户积分数据
	if err := user.UpdateOne(bson.M{
		"username": username,
	}, bson.M{
		"$inc": bson.M{
			"integral": task.Integral,
		},
	}); err != nil {
		return err
	}

	// 添加积分日志

	if err := log.AddOneIntegralLog(&log.IntegralLogSchema{
		UUID:     uuid.NewV1().String(),
		AddTime:  utils.Timestamp(),
		Username: username,
		Integral: task.Integral,
		Text:     text,
		Other:    "任务完成",
		Remark:   taskName,
	}); err != nil {
		return err
	}
	return nil
}

func bindAvatar(username string, avatar string) error {
	if avatar == "" {
		return errors.New("参数出错")
	}
	text := "上传头像"
	taskName := "UPLOAD_AVATAR"
	// 获取任务配置
	task, err := FindOneByTaskName("UPLOAD_AVATAR")
	if err != nil {
		return errors.New("没有找到这个任务！")
	}

	// 判读是否已经完成任务
	logs := log.FindManyIntegralLog(0, bson.M{
		"username": username,
		"text":     text,
	})
	if len(logs) > 0 {
		return errors.New("你已经完成任务！")
	}

	if err := user.UpdateOneByName(username, bson.M{
		"avatar": path.Join(config.Set.UploadImagePath, avatar),
	}); err != nil {
		return err
	}

	// 修改用户积分数据
	if err := user.UpdateOne(bson.M{
		"username": username,
	}, bson.M{
		"$inc": bson.M{
			"integral": task.Integral,
		},
	}); err != nil {
		return err
	}

	// 添加积分日志

	if err := log.AddOneIntegralLog(&log.IntegralLogSchema{
		UUID:     uuid.NewV1().String(),
		AddTime:  utils.Timestamp(),
		Username: username,
		Integral: task.Integral,
		Text:     text,
		Other:    "任务完成",
		Remark:   taskName,
	}); err != nil {
		return err
	}
	return nil
}

func playGame(username string) error {
	return errors.New("任务没有开通")
}

func lottery() (int64, error) {
	maxNum := 1000
	prizes, err := FindPrize()
	if err != nil {
		return -1, err
	}
	b := new(big.Int).SetInt64(int64(maxNum))
	i, err := rand.Int(rand.Reader, b)
	if err != nil {
		fmt.Printf("Can't generate random value: %v, %v", i, err)
		return -1, errors.New("抽奖失败")
	}

	prevNum := 0.0
	num := float64(i.Int64())
	for i, v := range *prizes {
		odds := v.Odds * float64(maxNum/100)
		if num == prevNum || num < odds+prevNum {

			return int64(i) + 1, nil

		} else {
			prevNum = prevNum + odds
		}
	}

	return -1, errors.New("抽奖失败")
}

func award(username string, num int64) (string, error) {
	tag := "积分抽奖"
	freeNum := 3
	subText := ""
	fee := 20
	// 检测免费抽奖额度是否使用完毕
	logs := log.FindManyIntegralLog(0, bson.M{
		"username": username,
		"text":     tag,
		"add_time": bson.M{
			"$gt": utils.DayStartTime(0),
			"$lt": utils.DayStartTime(1),
		},
	})
	if len(logs) < freeNum {
		// 免费
		subText = utils.JoinString("此次抽奖免费，你今天还有%v次免费机会。  ", freeNum-len(logs)-1)
	} else {
		// 收费 -扣取用户积分
		if _, err := user.FindOne(bson.M{
			"username": username,
			"integral": bson.M{
				"$gte": fee,
			},
		}); err != nil {
			return "", errors.New("您的余额不足")
		}

		// 扣取抽奖费用
		if err := user.UpdateOne(bson.M{
			"username": username,
		}, bson.M{
			"$inc": bson.M{
				"integral": -fee,
			},
		}); err != nil {
			return "", err
		}

		// 添加积分日志
		if err := log.AddOneIntegralLog(&log.IntegralLogSchema{
			ID:       primitive.ObjectID{},
			UUID:     uuid.NewV1().String(),
			AddTime:  utils.Timestamp(),
			Username: username,
			Integral: -int64(fee),
			Text:     tag,
			Other:    utils.JoinString("支付本次抽奖费用：%v积分。", fee),
		}); err != nil {
			return "", err
		}

	}

	// 获取奖品信息
	v, err := FindOnePrize(utils.JoinString("no%v", num))
	if err != nil {
		return "", err
	}

	// 发奖（添加用户积分）
	_ = user.UpdateOne(bson.M{
		"username": username,
	}, bson.M{
		"$inc": bson.M{
			"integral": v.Prize,
		},
	})

	text := ""
	if v.Prize > 0 {
		// 添加积分日志
		if err := log.AddOneIntegralLog(&log.IntegralLogSchema{
			ID:       primitive.ObjectID{},
			UUID:     uuid.NewV1().String(),
			AddTime:  utils.Timestamp(),
			Username: username,
			Integral: v.Prize,
			Text:     tag,
			Other:    utils.JoinString("你的奖品为：%v积分。", v.Prize),
		}); err != nil {
			return "", err
		}
		text = utils.JoinString("%v恭喜中奖，您的奖品为：%v积分！", subText, v.Prize)
	} else {
		text = utils.JoinString("%v很遗憾，您本次没有得到奖品！", subText)
	}
	return text, nil
}
